package com.junfeng.pet2048.util;

import com.junfeng.pet2048.entity.GameFrame;
import com.junfeng.pet2048.myenum.RedisKeyEnum;
import com.junfeng.pet2048.myenum.UserStatusEnum;
import com.junfeng.pet2048.server.WebSocketServer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 匹配缓存工具类
 */
@Component
public class ServerUtil {

    /**
     * 用户 uname 为 key，WebSocketServer 为 value
     */
    private static final Map<String, WebSocketServer> CLIENTS = new ConcurrentHashMap<>();

    /**
     * key 是标识存储用户在线状态的 RedisKeyEnum，value 为 map 类型，其中用户 uname 为 key，用户在线状态 为 value
     */
    @Resource
    private RedisTemplate<String, Map<String, String>> redisTemplate;

    @Resource
    private RedisTemplate<String, Object> stringRedisTemplate;

    /**
     * 添加客户端
     */
    public void addClient(String uname, WebSocketServer websocket) {
        CLIENTS.put(uname, websocket);
    }

    /**
     * 移除客户端
     */
    public void removeClinet(String uname) {
        if (getClient(uname) != null) {
            CLIENTS.remove(uname);
        }
    }

    /**
     * 获取客户端
     */
    public WebSocketServer getClient(String uname) {
        return CLIENTS.get(uname);
    }

    /**
     * 删除用户状态
     */
    public void deleteUserStatus(String uname) {
        UserStatusEnum status = getUserStatus(uname);
        if (status != null) {
            redisTemplate.opsForHash().delete(RedisKeyEnum.USER_STATUS.getKey(), uname);
        }
    }

    /**
     * 获取用户状态
     */
    public UserStatusEnum getUserStatus(String uname) {
        Object status = redisTemplate.opsForHash().get(RedisKeyEnum.USER_STATUS.getKey(), uname);
        if (status == null) {
            return null;
        }
        return UserStatusEnum.getStatusEnum(status.toString());
    }

    /**
     * 设置用户为 在线 状态
     */
    public void setUserOnLine(String uname) {
        deleteUserStatus(uname);
        redisTemplate.opsForHash().put(RedisKeyEnum.USER_STATUS.getKey(), uname, UserStatusEnum.ONLINE.getValue());
    }

    /**
     * 设置用户为 待匹配 状态
     */
    public void setUserWaitMatch(String uname) {
        deleteUserStatus(uname);
        redisTemplate.opsForHash().put(RedisKeyEnum.USER_STATUS.getKey(), uname, UserStatusEnum.WAIT_MATCH.getValue());
    }

    /**
     * 设置用户为 匹配中 状态
     */
    public void setUserInMatch(String uname) {
        deleteUserStatus(uname);
        redisTemplate.opsForHash().put(RedisKeyEnum.USER_STATUS.getKey(), uname, UserStatusEnum.IN_MATCH.getValue());
    }

    /**
     * 随机获取处于匹配状态的用户（除了指定用户外）
     */
    public String getUserInMatchRandom(String uname) {
        Optional<Map.Entry<Object, Object>> any = redisTemplate.opsForHash().entries(RedisKeyEnum.USER_STATUS.getKey())
                .entrySet().stream().filter(entry -> entry.getValue().equals(UserStatusEnum.IN_MATCH.getValue()) && !entry.getKey().equals(uname))
                .findAny();
        return any.map(entry -> entry.getKey().toString()).orElse(null);
    }

    /**
     * 设置用户为 游戏中 状态
     */
    public void setUserInGame(String uname) {
        deleteUserStatus(uname);
        redisTemplate.opsForHash().put(RedisKeyEnum.USER_STATUS.getKey(), uname, UserStatusEnum.IN_GAME.getValue());
    }

    /**
     * 设置用户为 待重连 状态
     */
    public void setUserWaitReConnect(String uname) {
        deleteUserStatus(uname);
        redisTemplate.opsForHash().put(RedisKeyEnum.USER_STATUS.getKey(), uname, UserStatusEnum.WAIT_RECONNECT.getValue());
    }

    /**
     * 设置用户为 掉线 状态
     */
    public void setUserOffLine(String uname) {
        deleteUserStatus(uname);
        redisTemplate.opsForHash().put(RedisKeyEnum.USER_STATUS.getKey(), uname, UserStatusEnum.OFFLINE.getValue());
    }

    /**
     * 设置处于游戏中的用户在同一房间
     */
    public void setUserInRoom(String uname1, String uname2) {
        redisTemplate.opsForHash().put(RedisKeyEnum.ROOM.getKey(), uname1, uname2);
        redisTemplate.opsForHash().put(RedisKeyEnum.ROOM.getKey(), uname2, uname1);
    }

    /**
     * 从房间中移除用户
     */
    public void removeUserFromRoom(String uname) {
        String userFromRoom = getUserFromRoom(uname);
        if(userFromRoom != null){
            redisTemplate.opsForHash().delete(RedisKeyEnum.ROOM.getKey(), uname);
        }
    }

    /**
     * 从房间中获取用户
     */
    public String getUserFromRoom(String uname) {
        Object obj = redisTemplate.opsForHash().get(RedisKeyEnum.ROOM.getKey(), uname);
        if (obj == null) {
            return null;
        } else {
            return obj.toString();
        }
    }

    /**
     * 设置分布式锁key
     */
    public void setLockKey(String uname, String lockKey) {
        redisTemplate.opsForHash().put(RedisKeyEnum.LOCK_KEY.getKey(), uname, lockKey);
    }

    /**
     * 获取分布式锁key
     */
    public String getLockKey(String uname) {
        Object obj = redisTemplate.opsForHash().get(RedisKeyEnum.LOCK_KEY.getKey(), uname);
        if (obj == null) {
            return null;
        } else {
            return obj.toString();
        }

    }

    /**
     * 移除分布式锁key
     */
    public void removeLockKey(String uname) {
        String lockKey = getLockKey(uname);
        if (lockKey != null) {
            redisTemplate.opsForHash().delete(RedisKeyEnum.LOCK_KEY.getKey(), uname);
        }
    }

    /**
     * 设置游戏帧
     */
    public void setGameFrame(String uname, GameFrame gameFrame) {
        List<GameFrame> gameFrameList = getGameFrameList(uname);
        if (gameFrameList == null) {
            gameFrameList = new ArrayList<>();
        }
        gameFrameList.add(gameFrame);
        removeGameFrame(uname);
        redisTemplate.opsForHash().put(RedisKeyEnum.GAME_FRAME.getKey(), uname, gameFrameList);
    }

    /**
     * 获取所有游戏帧
     */
    public List<GameFrame> getGameFrameList(String uname) {
        Object frame = redisTemplate.opsForHash().get(RedisKeyEnum.GAME_FRAME.getKey(), uname);
        return CastUtil.castList(frame, GameFrame.class);
    }

    /**
     * 移除游戏帧
     */
    public void removeGameFrame(String uname) {
        List<GameFrame> gameFrameList = getGameFrameList(uname);
        if (gameFrameList != null) {
            redisTemplate.opsForHash().delete(RedisKeyEnum.GAME_FRAME.getKey(), uname);
        }
    }

    /**
     * 获取分布式锁
     *
     * @param lockKey    key值
     * @param requestId  可为UUID，请求进来生成的UUID，作为value
     * @param expireTime 过期时间 单位为秒
     * @return 是否获取成功
     */
    public boolean tryGetDcsLock(String lockKey, String requestId, int expireTime) {
        return stringRedisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS);
    }

    /**
     * 删除获取分布式锁
     *
     * @param key
     */
    public boolean deleteDcsLock(String key) {
        Object obj = getDcsLock(key);
        if(obj == null){
            return false;
        }else{
            return stringRedisTemplate.delete(key);
        }
    }

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */

    public Object getDcsLock(String key) {
        Object obj = stringRedisTemplate.opsForValue().get(key);
        if(obj == null){
            return null;
        }else{
            return obj;
        }
    }


}